import * as THREE from 'three'
import '../../../../../../common/utils/threeLoader'
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

export default class ModelPreviewer {
  private static instance: ModelPreviewer
  private scene: THREE.Scene
  private camera: THREE.Camera
  private controls: OrbitControls
  private renderer: THREE.WebGLRenderer
  private directionLight: THREE.DirectionalLight
  private animationFrameId: number

  private constructor() { }
  public static getInstance(): ModelPreviewer {
    if (!ModelPreviewer.instance) {
      ModelPreviewer.instance = new ModelPreviewer();
    }
    return ModelPreviewer.instance;
  }

  public init(container: HTMLElement) {
    // ==== 创建场景 ====
    this.scene = new THREE.Scene();
    // ==== 创建一个点光源 ====
    // const light = new THREE.PointLight(0xffffff, 0.5)
    // light.position.set(150, 150, 150)
    // 环境光
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
    this.scene.add(ambientLight)
    this.directionLight = new THREE.DirectionalLight(0xffffff, 0.5)
    this.scene.add(this.directionLight)

    // ==== 创建一个透视投影相机对象 ====
    // this.camera = new THREE.PerspectiveCamera(10, 1, 1, 30000)
    this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 1, 30000)
    // 设置相机的位置
    this.camera.position.set(1, 1, 1)
    // 定义相机的视线 观察目标点的坐标
    this.camera.lookAt(0, 0, 0)

    // ==== 创建一个渲染器对象 ====
    this.renderer = new THREE.WebGLRenderer({
      antialias: true, // 抗锯齿
    })
    this.renderer.setPixelRatio(window.devicePixelRatio || 1)
    this.renderer.setClearColor(0XFFFFFF)
    this.renderer.setSize(600, 600)
    this.renderer.render(this.scene, this.camera)

    // ==== 设置相机控件归到控制器 ====
    this.controls = new OrbitControls(this.camera, this.renderer.domElement)
    // controls.addEventListener('change', () => {
    //     renderer.render(scene, camera)
    //     console.log('camera.position', camera.position)
    // })
    this.controls.autoRotateSpeed = 5
    this.controls.autoRotate = false

    // const container = document.getElementById(containerId)
    container.appendChild(this.renderer.domElement)
  }

  public loadObj(url: string) {
    const loader = new OBJLoader()
    loader.load(url, (object) => {
      console.log('加载完成时的回调函数', object)
      object.scale.set(0.01, 0.01, 0.01)
      // 设置模型材质
      object.traverse(function (child) {
        console.log('traverse', child)
        if (child instanceof THREE.Mesh) {
          child.material = new THREE.MeshStandardMaterial({
            color: 0xCCCCCC,
            roughness: 1,
            side: THREE.DoubleSide
          })
        }
      })

      // 添加模型到场景中
      this.scene.add(object)
      this.centerCamera(object)
      this.renderer.render(this.scene, this.camera)
    })
  }

  public animate() {
    this.animationFrameId = requestAnimationFrame(() => this.animate())

    this.controls && this.controls.update()
    this.directionLight && this.directionLight.position.copy(this.camera.position)

    this.renderer && this.renderer.render(this.scene, this.camera)
  }

  public centerCamera(object: THREE.Object3D) {
    // const box3 = new THREE.Box3()
    // box3.setFromObject(object)
    // const center = box3.getCenter(new THREE.Vector3())
    // const distance = box3.getSize(new THREE.Vector3()).length()
    // const cameraOffset = distance / Math.tan(THREE.MathUtils.degToRad(this.camera.fov * 0.6))
    // const cameraPosition = center.clone().add(new THREE.Vector3(0, 0, cameraOffset))
    // this.camera.position.copy(cameraPosition)
    // this.controls.target.copy(center)
    // // 更新OrbitControls
    // this.controls.update()

    // 根据模型的尺寸和相机的视角调整相机位置和透视投影
    const boundingBox = new THREE.Box3()
    boundingBox.setFromObject(object)
    const center = boundingBox.getCenter(new THREE.Vector3())
    this.controls.target.copy(center)

    const modelSize = boundingBox.getSize(new THREE.Vector3())
    const modelBoundingSphereRadius = modelSize.length() * 0.5

    if (this.camera instanceof THREE.OrthographicCamera) {
      // 计算适当的zoom值，使模型最大化显示
      const maxModelSize = Math.max(modelSize.x, modelSize.y, modelSize.z)
      // const aspect = window.innerWidth / window.innerHeight
      const distance = maxModelSize / (2 * Math.tan(this.camera.top * Math.PI / 360))
      // this.initZoom = 2 / maxModelSize // 模型越大，zoom越小；其中 2 是经验值
      this.camera.zoom = 1 / maxModelSize // 模型越大，zoom越小；其中 2 是经验值
      this.camera.position.set(0, 0, distance)
      this.camera.updateProjectionMatrix()
    }
  }

  public dispose() {
    console.log('dispose', this.animationFrameId)
    if (!this.renderer) return
    try {
      cancelAnimationFrame(this.animationFrameId); // animationFrameId = requestAnimationFrame(this.render);
      this.renderer.dispose();
      this.renderer.forceContextLoss();
      this.renderer['content'] = null;
      let gl = this.renderer.domElement.getContext("webgl");
      if (gl && gl.getExtension("WEBGL_lose_context")) {
        gl.getExtension("WEBGL_lose_context").loseContext();
      }
      this.renderer = null;
      this.camera = null;
      this.scene.traverse((child) => {
        if (child['material']) {
          child['material'].dispose();
        }
        if (child['geometry']) {
          child['geometry'].dispose();
        }
        child = null;
      });
      this.scene = null;
    } catch (e) {
      console.error('Failed to destroy threejs', e);
    }
  }
}